﻿using System;
using System.Collections.Generic;
using OpenCvSharp;
using System.Net.Http;
using Sdcb.PaddleInference;
using Sdcb.PaddleOCR.Models;
using Sdcb.PaddleOCR;
using Sdcb.PaddleOCR.Models.Local;
using System.Text.RegularExpressions;
using System.IO;
using FeiJiangOCR.OCRModel;
using System.Linq;

namespace FeiJiangOCR
{
    public class InvoiceOCRHelper
    {
        public static InvoiceModel IdentifyLocalCard(string fileNamePath)
        {
            List<string> wordKeys = new List<string> { "金额", "税率", "税额", "（小写）" };
            Dictionary<string, Point> dic = new Dictionary<string, Point>();
            InvoiceModel invoiceModel = new InvoiceModel();
            List<InvoiceTextModel> invoiceTextModelList = new List<InvoiceTextModel>();
            FullOcrModel model = LocalFullModels.ChineseV3;
            // 下面的PaddleDevice.Mkldnn()是新加的
            // 之前是用的PaddleConfig.Defaults.UseMkldnn = true
            // 如果想要GPU，则改为PaddleDevice.Gpu()即可 PaddleDevice.Mkldnn()
            using (PaddleOcrAll all = new PaddleOcrAll(model, PaddleDevice.Mkldnn())
            {
                AllowRotateDetection = true, /* 允许识别有角度的文字 */
                Enable180Classification = false, /* 不允许识别旋转角度大于90度的文字 */
            })
            {
                // 如果需要读取本地文件，使用如下被注释的代码
                using (Mat src2 = Cv2.ImRead(fileNamePath, ImreadModes.Color))
                {
                    PaddleOcrResult result = all.Run(src2);
                   // Console.WriteLine("Detected all texts: \n" + result.Text);
                    foreach (PaddleOcrResultRegion region in result.Regions)
                    {
                      // Console.WriteLine($"Text: {region.Text}, Score: {region.Score}, RectCenter: {region.Rect.Center}, RectSize:    {region.Rect.Size}, Angle: {region.Rect.Angle}");
                        InvoiceTextModel invoiceTextModel = new InvoiceTextModel();
                        invoiceTextModel.X = region.Rect.Center.X;
                        invoiceTextModel.Y = region.Rect.Center.Y;
                        invoiceTextModel.RegionsText = region.Text;
                        invoiceTextModelList.Add(invoiceTextModel);
                        if (wordKeys.Any(x => x == region.Text))
                        {
                            Point point = new Point(region.Rect.Center.X, region.Rect.Center.Y);
                            dic[region.Text] = point;
                        }

                        if (region.Text.Contains("发票号码") || region.Text.ToUpper().Contains("NO"))
                        {
                            var regex = new Regex("\\d*$");
                            var mc = regex.Match(region.Text);
                            if (mc.Success)
                            {
                                invoiceModel.InvoiceNo = mc.Value.Substring(0, 8);
                            }
                        }
                        if (region.Text.Contains("发票代码"))
                        {
                            string tempInvoiceCode = region.Text.Replace("发票代码", "").Replace(":", "").Replace("：", "");
                            invoiceModel.InvoiceCode = tempInvoiceCode;

                        }
                        if (region.Text.Contains("开票日期"))
                        {
                            var regex = new Regex("\\d{4}年\\d{2}月\\d{2}日");
                            var mc = regex.Match(region.Text);
                            if (mc.Success)
                            {
                                DateTime time = Convert.ToDateTime(mc.Value.Replace("年", "/").Replace("月", "/").Replace("日", ""));
                                invoiceModel.InvoiceDate = time.ToString();
                            }
                            else
                            {
                                string tempStr = region.Text.Replace("开票日期", "").Replace(":", "").Replace("：", "");
                                invoiceModel.InvoiceDate = tempStr;
                            }
                        }
                    }
                }
            }
            //查找 金额（不含税）
            if (dic.ContainsKey("金额"))
            {
                Point jePoint = dic["金额"];
                var tempList = GetInvoiceText(jePoint, invoiceTextModelList);
                tempList = tempList.Where(x => x.RegionsText.Contains("￥")).ToList();
                if (tempList != null)
                {
                    if (tempList.Count == 1)
                    {
                        string tempStr = tempList[0].RegionsText.Replace("￥", "");
                        decimal.TryParse(tempStr, out decimal tempVal);
                        invoiceModel.ExcludingTax = tempVal;
                    }
                    if (tempList.Count > 1)
                    {
                        var tempInvoices = tempList.OrderBy(x => x.X).Take(1).ToList();
                        string tempStr = tempInvoices[0].RegionsText.Replace("￥", "");
                        decimal.TryParse(tempStr, out decimal tempVal);
                        invoiceModel.ExcludingTax = tempVal;
                    }
                }
            }

            //查找税率
            if (dic.ContainsKey("税率"))
            {
                Point slPoint = dic["税率"];
                var tempList = GetInvoiceText(slPoint, invoiceTextModelList);
                tempList = tempList.Where(x => x.RegionsText.Contains("%")).ToList();
                //获取到 含税金额和不含税金额，这里取不含税金额
                if (tempList != null)
                {
                    if (tempList.Count == 1)
                    {
                        string templvStr = tempList[0].RegionsText.Replace("%", "");
                        decimal.TryParse(templvStr, out decimal tempValue);
                        invoiceModel.TaxRate = tempValue;
                    }
                    if (tempList.Count > 1)
                    {
                        var tempInvoices = tempList.OrderBy(x => x.X).Take(1).ToList();
                        string templvStr = tempInvoices[0].RegionsText.Replace("%", "");
                        decimal.TryParse(templvStr, out decimal tempValue);
                        invoiceModel.TaxRate = tempValue;
                    }
                }
            }
            //查找含税价
            if (dic.ContainsKey("（小写）"))
            {
                Point slPoint = dic["（小写）"];
                var tempList = GetTotoal(slPoint, invoiceTextModelList);
                tempList = tempList.Where(x => x.RegionsText.Contains("￥")).ToList();
                if (tempList != null)
                {
                    if (tempList.Count == 1)
                    {
                        string tempStr = tempList[0].RegionsText.Replace("￥", "");
                        decimal.TryParse(tempStr, out decimal tempVal);
                        invoiceModel.InvoiceIncludingTax = tempVal;
                    }
                    if (tempList.Count > 1)
                    {
                        var tempInvoices = tempList.OrderBy(x => x.X).Take(1).ToList();
                        string tempStr = tempInvoices[0].RegionsText.Replace("￥", "");
                        decimal.TryParse(tempStr, out decimal tempVal);
                        invoiceModel.InvoiceIncludingTax = tempVal;
                    }
                }
            }
            if (string.IsNullOrWhiteSpace(invoiceModel.InvoiceCode))
            {
                //根据发票代码 位数 推测 发票代码
               var tempCodeModel= invoiceTextModelList.Find(x => !string.IsNullOrEmpty(x.RegionsText) && (x.RegionsText.Length == 10 || x.RegionsText.Length == 12));
                if (tempCodeModel != null)
                {
                    invoiceModel.InvoiceCode = tempCodeModel.RegionsText;
                }
            }

            return invoiceModel;
        }

        private static List<InvoiceTextModel> GetInvoiceText(Point point, List<InvoiceTextModel> invoiceTextModels)
        {
            int xstep = 50;
            int ystep = 100;
            int textX = point.X;
            int textY = point.Y;
            List<InvoiceTextModel> resultTexts = null;
            //向左查找
            int leftX = textX - xstep;
            for (int i = 0; i < 10; i++)
            {
                var textModelArray = invoiceTextModels.Where(x => x.X >= leftX).ToList();
                if (textModelArray != null && textModelArray.Count > 0)
                {
                    resultTexts = textModelArray;
                    break;
                }
                leftX = leftX - xstep;
            }
            if (resultTexts == null)
            {
                //向右查找
                int rightX = textX + xstep;
                for (int i = 0; i < 10; i++)
                {
                    var textModelArray = invoiceTextModels.Where(x => x.X >= rightX).ToList();
                    if (textModelArray != null && textModelArray.Count > 0)
                    {
                        resultTexts = textModelArray;
                        break;
                    }
                    rightX = rightX + xstep;
                }
            }

            return resultTexts;

        }

        private static List<InvoiceTextModel> GetTotoal(Point point, List<InvoiceTextModel> invoiceTextModels)
        {
            int xstep = 50;
            int ystep = 100;
            int textX = point.X;
            int textY = point.Y;
            List<InvoiceTextModel> resultTexts = null;
            //向右查找
            int rightX = textX + xstep;
            for (int i = 0; i < 10; i++)
            {
                var textModelArray = invoiceTextModels.Where(x => x.X >= rightX).ToList();
                if (textModelArray != null && textModelArray.Count > 0)
                {
                    resultTexts = textModelArray;
                    break;
                }
                rightX = rightX + xstep;
            }

            return resultTexts;

        }
        /// <summary>
        /// 识别远程图像
        /// </summary>
        /// <param name="onLineFileUrl">远程路径 如 https://www.tp-link.com.cn/content/images2017/gallery/4288_1920.jpg</param>
        public static void IdentifyOnLineIDCard(string onLineFileUrl)
        {


            // 注：需要先安装如下NuGet包：
            // * Sdcb.PaddleInference
            // * Sdcb.PaddleOCR
            // * Sdcb.PaddleOCR.Models.LocalV3
            // * Sdcb.PaddleInference.runtime.win64.mkl
            // * OpenCvSharp4.runtime.win


            byte[] sampleImageData;
            using (HttpClient http = new HttpClient())
            {
                Console.WriteLine("Download sample image from: " + onLineFileUrl);
                var task = http.GetByteArrayAsync(onLineFileUrl);
                sampleImageData = task.Result;
                //异步，提高TPS
                //sampleImageData = await http.GetByteArrayAsync(onLineFileUrl);
            }

            FullOcrModel model = LocalFullModels.ChineseV4;
            // 下面的PaddleDevice.Mkldnn()是新加的
            // 之前是用的PaddleConfig.Defaults.UseMkldnn = true
            // 如果想要GPU，则改为PaddleDevice.Gpu()即可
            using (PaddleOcrAll all = new PaddleOcrAll(model, PaddleDevice.Mkldnn())
            {
                AllowRotateDetection = true, /* 允许识别有角度的文字 */
                Enable180Classification = false, /* 不允许识别旋转角度大于90度的文字 */
            })
            {
                using (Mat src = Cv2.ImDecode(sampleImageData, ImreadModes.Color))
                {

                    PaddleOcrResult result = all.Run(src);
                    Console.WriteLine("Detected all texts: \n" + result.Text);
                    foreach (PaddleOcrResultRegion region in result.Regions)
                    {
                        Console.WriteLine($"Text: {region.Text}, Score: {region.Score}, RectCenter: {region.Rect.Center}, RectSize:    {region.Rect.Size}, Angle: {region.Rect.Angle}");
                    }

                    foreach (PaddleOcrResultRegion region in result.Regions)
                    {
                        //RotatedRect rotatedRect = new RotatedRect();
                        //string text = string.Empty;
                        //float score = 0;

                        //region.Deconstruct(out rotatedRect,out text,out score);
                        //Console.WriteLine(rotatedRect.Center+"**"+ text+"**"+ score);
                        string name = Guid.NewGuid().ToString() + ".jpg";


                        // Console.WriteLine($"Text: {region.Text},Name：{name}");

                        //Point point = region.Rect.Center.ToPoint();
                        //Size size = new Size(region.Rect.Size.Width, region.Rect.Size.Height);
                        //Rect rect = new Rect(point, size);

                        //var ddd = src2[rect];

                    }
                    Console.WriteLine("****************");
                }
            }
        }


    }

}

